/*-------------------------------------------------------------------------
 *
 * queryenvironment.c
 *	  查询环境，用于存储上下文特定的值，如临时命名
 *	  关系。初步使用是为了存储来自“正常”关系的
 *	  增量信息的命名元组存储。
 *
 * 初始实现使用列表，因为在任何一个上下文中，此类关系的数量
 * 预计是非常少的。如果这成为性能问题，实施可以更改，而不会对
 * 调用者造成其他影响，因为这是一个不透明的结构。这就是需要
 * 创建函数的原因。
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, 加利福尼亚大学董事会
 *
 *
 * IDENTIFICATION
 *	  src/backend/utils/misc/queryenvironment.c
 *
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

#include "access/table.h"
#include "utils/queryenvironment.h"
#include "utils/rel.h"

/*
 * 查询环境的私有状态。
 */
struct QueryEnvironment
{
	List	   *namedRelList;
};


QueryEnvironment *
create_queryEnv(void)
{
	return (QueryEnvironment *) palloc0(sizeof(QueryEnvironment));
}

EphemeralNamedRelationMetadata
get_visible_ENR_metadata(QueryEnvironment *fc_queryEnv, const char *fc_refname)
{
	EphemeralNamedRelation fc_enr;

	Assert(fc_refname != NULL);

	if (fc_queryEnv == NULL)
		return NULL;

	fc_enr = get_ENR(fc_queryEnv, fc_refname);

	if (fc_enr)
		return &(fc_enr->md);

	return NULL;
}

/*
 * 在给定环境中注册一个命名关系以供使用。
 *
 * 如果这仅用于规划目的，tstate 字段可以留为空；
 */
void register_ENR(QueryEnvironment *fc_queryEnv, EphemeralNamedRelation fc_enr)
{
	Assert(fc_enr != NULL);
	Assert(get_ENR(fc_queryEnv, fc_enr->md.name) == NULL);

	fc_queryEnv->namedRelList = lappend(fc_queryEnv->namedRelList, fc_enr);
}

/*
 * 通过名称注销一个短期关系。这可能是一个很少使用的功能，但似乎应该提供“以防万一”。
 */
void unregister_ENR(QueryEnvironment *fc_queryEnv, const char *fc_name)
{
	EphemeralNamedRelation fc_match;

	fc_match = get_ENR(fc_queryEnv, fc_name);
	if (fc_match)
		fc_queryEnv->namedRelList = list_delete(fc_queryEnv->namedRelList, fc_match);
}

/*
 * 如果在给定集合中找到名称匹配，则返回一个 ENR。如果未找到匹配项，
 * 必须安静地返回 NULL。
 */
EphemeralNamedRelation
get_ENR(QueryEnvironment *fc_queryEnv, const char *fc_name)
{
	ListCell   *fc_lc;

	Assert(fc_name != NULL);

	if (fc_queryEnv == NULL)
		return NULL;

	foreach(fc_lc, fc_queryEnv->namedRelList)
	{
		EphemeralNamedRelation fc_enr = (EphemeralNamedRelation) lfirst(fc_lc);

		if (strcmp(fc_enr->md.name, fc_name) == 0)
			return fc_enr;
	}

	return NULL;
}

/*
 * 获取基于填充字段的短期命名关系的 TupleDesc。
 *
 * 当 TupleDesc 基于目录中的关系时，我们依赖于该关系同时被使用，
 * 因此适当的锁将处于持有状态。这里的锁定无论如何都太晚了。
 */
TupleDesc ENRMetadataGetTupDesc(EphemeralNamedRelationMetadata fc_enrmd)
{
	TupleDesc	fc_tupdesc;

	/* 这些字段中必须且仅必须填入一个。 */
	Assert((fc_enrmd->reliddesc == InvalidOid) != (fc_enrmd->tupdesc == NULL));

	if (fc_enrmd->tupdesc != NULL)
		fc_tupdesc = fc_enrmd->tupdesc;
	else
	{
		Relation	fc_relation;

		fc_relation = table_open(fc_enrmd->reliddesc, NoLock);
		fc_tupdesc = fc_relation->rd_att;
		table_close(fc_relation, NoLock);
	}

	return fc_tupdesc;
}
